/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.inspur.edp.lcm.metadata.core;

import com.inspur.edp.i18n.resource.api.II18nResourceDTManager;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.I18nResource;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.entity.MetadataType;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.common.configuration.I18nManagerHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataTypeHelper;
import com.inspur.edp.lcm.metadata.spi.MetadataI18nService;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.io.File;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

public class I18nCoreService {
    private static I18nCoreService sigleton = null;

    private final MetadataCoreManager metadataCoreManager = new MetadataCoreManager();

    private final String resourceMetadataType = "ResourceMetadata";
    private final String linguisticResourceMetadataType = "LinguisticResource";

    public static I18nCoreService getInstance() {
        if (sigleton == null) {
            sigleton = new I18nCoreService();
        }
        return sigleton;
    }

    public GspMetadata extractResourceMetadata(GspMetadata metadata, String absolutePath) {
        GspMetadata baseMetadata;
        File metadataFile = new File(absolutePath);
        if (metadata.getHeader().getTranslating()) {
            baseMetadata = metadataCoreManager.loadMetadata(metadataFile.getName(), metadataFile.getParent());
        } else {
            baseMetadata = metadata;
        }
        // 根据基础元数据抽取元数据
        GspMetadata resourceMetadata = buildResourceMetadata(baseMetadata, absolutePath);
        String dirPath = metadataFile.getParent();
        // 建立基础元数据与资源元数据的关联关系
        MetadataReference ref = buildRefs(baseMetadata, resourceMetadata);
        if (metadata.getRefs() != null && metadata.getRefs().stream().noneMatch(r -> r.getDependentMetadata().getId().equals(ref.getDependentMetadata().getId()))) {
            metadata.getRefs().add(ref);
        }

        String resouceMetadataPath = Paths.get(dirPath).resolve(resourceMetadata.getHeader().getFileName()).toString();
        if (metadataCoreManager.isMetadataExist(resouceMetadataPath)) {
            metadataCoreManager.saveMetadata(resourceMetadata, resouceMetadataPath);
        } else {
            metadataCoreManager.createMetadata(dirPath, resourceMetadata);
        }

        return resourceMetadata;
    }

    public boolean isI18nMetadata(GspMetadata metadata) {
        return metadata.getHeader().getTranslating();
    }

    private GspMetadata buildResourceMetadata(GspMetadata metadata, String absolutePath) {
        I18nResource resouceItem = getResouceItem(metadata);
        // 判断是否存在资源元数据
        String resourceMetadataFileName = getResourceMetadataFileName(metadata);
        String resourceMetadataPath = Paths.get(new File(absolutePath).getParent()).resolve(resourceMetadataFileName).toString();
        MetadataCoreManager metadataCoreManager = new MetadataCoreManager();
        boolean metadataExist = metadataCoreManager.isMetadataExist(resourceMetadataPath);
        GspMetadata resourceMetadata;
        File file = new File(resourceMetadataPath);
        if (metadataExist) {
            resourceMetadata = metadataCoreManager.loadMetadata(resourceMetadataFileName, file.getParent());
        } else {
            resourceMetadata = new GspMetadata();
            MetadataHeader header = new MetadataHeader();
            header.setId(UUID.randomUUID().toString());
            FileServiceImp fileService = new FileServiceImp();
            String fileNameWithoutExtension = fileService.getFileNameWithoutExtension(resourceMetadataFileName);
            header.setCode(fileNameWithoutExtension);
            header.setName(fileNameWithoutExtension);
            header.setFileName(resourceMetadataFileName);
            header.setNameSpace(metadata.getHeader().getNameSpace());
            header.setBizObjectId(metadata.getHeader().getBizObjectId());
            header.setType(resourceMetadataType);
            resourceMetadata.setHeader(header);
        }
        II18nResourceDTManager i18nResourceDTManager = SpringBeanUtils.getBean(II18nResourceDTManager.class);
        i18nResourceDTManager.getResourceMetadata(resourceMetadata, resouceItem);
        return resourceMetadata;
    }

    private MetadataReference buildRefs(GspMetadata baseMetadata, GspMetadata resouceMetadata) {
        MetadataReference metadataReference = new MetadataReference();
        metadataReference.setMetadata(baseMetadata.getHeader());
        metadataReference.setDependentMetadata(resouceMetadata.getHeader());
        if (baseMetadata.getRefs().stream().noneMatch(item -> item.getDependentMetadata().getId().equals(resouceMetadata.getHeader().getId()))) {
            baseMetadata.getRefs().add(metadataReference);
        }
        return metadataReference;
    }

    private I18nResource getResouceItem(GspMetadata metadata) {
        MetadataI18nService manager = getI18nManager(metadata.getHeader().getType());
        I18nResource resourceItem = manager.getResourceItem(metadata);
        return resourceItem;
    }

    private MetadataI18nService getI18nManager(String type) {
        MetadataI18nService i18nManager = I18nManagerHelper.getInstance().getI18nManager(type);
        if (i18nManager == null) {
            throw new RuntimeException("获取当前元数据国际化扩展实现类失败，当前元数据类型为" + type);
        }
        return i18nManager;
    }

    private String getResourceMetadataFileName(GspMetadata metadata) {
        String metadataSuffix = getMetadataSuffix(metadata.getHeader().getType());
        String resourceMetadataSuffix = getMetadataSuffix(resourceMetadataType);
        return metadata.getHeader().getCode() + metadataSuffix + resourceMetadataSuffix;
    }

    private String getMetadataSuffix(String type) {
        MetadataType metadataType = MetadataTypeHelper.getInstance().getMetadataTypes().stream().filter(mt -> type.equals(mt.getTypeCode())).findFirst().orElse(null);
        Utils.checkNPE(metadataType, "此类型元数据：" + type + "，在配置文件中不存在。");
        return metadataType.getPostfix();
    }

    public void extractLanguageMetadata(GspMetadata metadata, GspMetadata resourceMetadata, String path) {
        GspMetadata i18nResourceMetadata = buildResourceMetadata(metadata, path);
        if (i18nResourceMetadata != null) {
            i18nResourceMetadata.getHeader().setLanguage(metadata.getHeader().getLanguage());
            saveLanguageMetadata(metadata, resourceMetadata, i18nResourceMetadata, path);
        }
    }

    public GspMetadata getI18nMetadata(String fileName, String absolutePath, String language) {
        GspMetadata metadata = metadataCoreManager.loadMetadata(fileName, absolutePath);
        List<I18nResource> i18nResourceList = getResourceWithMetadata(metadata, language);
        MetadataI18nService i18nManager = I18nManagerHelper.getInstance().getI18nManager(metadata.getHeader().getType());
        if (i18nManager != null) {
            return i18nManager.merge(metadata, i18nResourceList);
        }
        return metadata;
    }

    private List<I18nResource> getResourceWithMetadata(GspMetadata metadata, String language) {
        II18nResourceDTManager i18nResourceDTManager = SpringBeanUtils.getBean(II18nResourceDTManager.class);
        List<I18nResource> i18nResourceList = i18nResourceDTManager.getI18nResource(metadata, language);
        List<I18nResource> collect = i18nResourceList.stream().filter(resource -> resource.getLanguage().equals(language)).collect(Collectors.toList());
        return collect;
    }

    private void saveLanguageMetadata(GspMetadata metadata, GspMetadata resourceMetadata,
        GspMetadata i18nResourceMetadata, String path) {
        // 判断是否存在资源元数据
        String languageMetadataFileName = getLanguageMetadataFileName(metadata);
        String languageMetadataPath = Paths.get(new File(path).getParent()).resolve(languageMetadataFileName).toString();
        MetadataCoreManager metadataCoreManager = new MetadataCoreManager();
        boolean metadataExist = metadataCoreManager.isMetadataExist(languageMetadataPath);
        GspMetadata languageMetadata;
        File file = new File(languageMetadataPath);
        if (metadataExist) {
            languageMetadata = metadataCoreManager.loadMetadata(languageMetadataFileName, file.getParent());
        } else {
            languageMetadata = new GspMetadata();
            MetadataHeader header = new MetadataHeader();
            header.setId(UUID.randomUUID().toString());
            FileServiceImp fileService = new FileServiceImp();
            String fileNameWithoutExtension = fileService.getFileNameWithoutExtension(languageMetadataFileName);
            header.setCode(fileNameWithoutExtension);
            header.setName(fileNameWithoutExtension);
            header.setFileName(languageMetadataFileName);
            header.setNameSpace(metadata.getHeader().getNameSpace());
            header.setBizObjectId(metadata.getHeader().getBizObjectId());
            header.setType(linguisticResourceMetadataType);
            languageMetadata.setHeader(header);
        }
        II18nResourceDTManager i18nResourceDTManager = SpringBeanUtils.getBean(II18nResourceDTManager.class);
        IMetadataContent content = i18nResourceDTManager.extract(resourceMetadata, i18nResourceMetadata);
        languageMetadata.setContent(content);
        if (metadataExist) {
            metadataCoreManager.createMetadata(languageMetadataPath, languageMetadata);
        } else {
            metadataCoreManager.saveMetadata(languageMetadata, languageMetadataPath);
        }
    }

    private String getLanguageMetadataFileName(GspMetadata metadata) {
        String language = metadata.getHeader().getLanguage();
        String metadataSuffix = getMetadataSuffix(metadata.getHeader().getType());
        String linguisticMetadataSuffix = getMetadataSuffix(linguisticResourceMetadataType);
        return metadata.getHeader().getCode() + metadataSuffix + "." + language + linguisticMetadataSuffix;
    }
}
